<template>
  <!-- 节点 -->
  <div
    class="node-capsule-component"
    :style="{
      width: `${nodeWidth - 4}px`,
      height: `${nodeHeight - 4}px`,
    }"
    @click="selectNode($event)"
    @dblclick="selectCircleNode($event)"
    @mouseenter="isNodeHovered = true"
    @mouseleave="isNodeHovered = false"
  >
    <!-- 节点胶囊 :class="{'node-capsule-running' : nodeStatus.status === 'RUNNING'}" -->
    <!--  background: nodeStatus.status === 'RUNNING' ? `linear-gradient(90deg, #fff 25%, #c5c9ff 37%, #fff 63%)` : '#fff' -->
    <a-dropdown
      :trigger="[mode ? '' : 'contextmenu']"
      :overlay-style="{ width: '100px' }"
      :visible="node.id === menuOpenId && contextmenuVisible"
      @visibleChange="visibleChange"
    >
      <!-- 胶囊 -->
      <div class="dropdown-capsule">
        <!-- 禁用灰度 -->
        <div
          class="node-no-forbidden"
          :class="{ 'node-forbidden': node.data.forbidden }"
        ></div>
        <!-- 节点图标 -->
        <a-popover v-if="node.type === 1">
          <div slot="title" style="color: rgba(0, 0, 0, 0.65);">关键指数</div>
          <template slot="content">
            <p v-for="(item, index) in getDetailText(node)" :key="index">
              {{ item }}
            </p>
          </template>
          <div
            class="type-icon"
            :style="{
              'font-size': `${decimalZoomScale * 34}px`,
              height: `${nodeHeight - 6}px`,
              width: `${nodeHeight - 6}px`,
            }"
          >
            <a-icon-font class="type-icon-color" :type="iconInfo('icon')" />
          </div>
        </a-popover>
        <div
          v-else
          class="type-icon"
          :style="{
            'font-size': `${decimalZoomScale * 34}px`,
            height: `${nodeHeight - 6}px`,
            width: `${nodeHeight - 6}px`,
          }"
        >
          <a-icon-font class="type-icon-color" :type="iconInfo('icon')" />
          <!-- <a-icon-font :type="groupIcon(node.type)"/> -->
        </div>

        <!-- 节点名称 -->
        <a-tooltip placement="top" :mouse-enter-delay="4">
          <template slot="title">
            <span>{{ node.name }}</span>
          </template>
          <!-- <div class="node-name" :style="{width: calcNameWidth + 'px', 'font-size': `${ decimalZoomScale * 12}px`, bottom:0}" @dblclick="doubleClickName(node, $event)"> -->
          <div
            class="node-name"
            :style="{
              width: calcNameWidth + 'px',
              'font-size': `${decimalZoomScale * 12}px`,
              top: nodeHeight + 3 + 'px',
            }"
            @dblclick="doubleClickName(node, $event)"
          >
            <div
              v-if="!editStatus"
              class="normal-display"
              :class="{ 'node-forbidden-name': node.data.forbidden }"
            >
              {{ node.name }}
            </div>
            <div v-else class="edit-name" @click="$event.stopPropagation()">
              <a-input
                ref="nameInput"
                v-model="editName"
                v-focus
                type="text"
                :size="'small'"
                @keyup.enter.native="$event.target.blur"
                @blur="editNameEnter"
                @mousedown="$event.stopPropagation()"
              />
            </div>
            <a-icon-font
              v-if="comment"
              type="iconzujiandaohang-beifen3"
              :style="{
                backgroundColor: isCommentReadShow ? '#c5c9ff' : '#fff',
                borderRadius: '2px',
                opacity: 0.5,
              }"
              @click.stop="showHideComment"
            />
          </div>
        </a-tooltip>
        <!-- 附表 toggle icon -->
        <slot
          v-if="!editStatus"
          name="toggleNode"
          class="menu-hover-ellipsis"
        ></slot>

        <!-- 节点状态 -->
        <div
          v-if="!comparisonStatus"
          class="status-icon-content"
          :style="{
            'font-size': `${decimalZoomScale * 18}px`,
            height: `${nodeHeight - 22}px`,
            width: `${nodeHeight - 22}px`,
            left: `${nodeWidth - 12}px`,
          }"
        >
          <a-tooltip
            v-if="nodeStatus.status.length > 0 && node.type !== 6"
            placement="top"
          >
            <template slot="title">
              <span>{{ nodeStatus.tip || '无信息' }}</span>
            </template>
            <div v-if="!!nodeStatusIcon" class="status-icon">
              <a-icon-font :type="nodeStatusIcon" />
            </div>
          </a-tooltip>

          <div
            v-else-if="node.type === 6 && node.parentId.length < 1"
            class="status-icon"
          >
            <a-icon-font type="iconweiwanpeizhi" />
          </div>
        </div>
        <!-- 可视化对比 -->
        <div
          v-if="comparisonStatus"
          class="comparison-select"
          :style="{
            'font-size': `${decimalZoomScale * 24}px`,
            height: `${nodeHeight - 8}px`,
            width: `${nodeHeight - 8}px`,
            'align-items': 'center',
            display: 'flex',
            'justify-content': 'center',
          }"
          @click="changeNodeComparison($event)"
        >
          <a-icon-font
            v-if="comparisonNodeIds.includes(node.id)"
            type="iconxuanzeanniu2"
          />
          <a-icon-font v-else type="iconxuanzeanniu1" />
        </div>
        <!-- 后面添加节点 btn -->
        <slot name="add"></slot>
      </div>
      <!-- 编辑菜单 -->
      <a-menu slot="overlay" @click="contextmenuVisible = false">
        <a-menu-item v-if="isOperatorNode" @click="openNodeEditor()"
          >编辑</a-menu-item
        >
        <a-menu-item v-if="!node.data.forbidden" @click="nodeCopy()"
          >复制</a-menu-item
        >
        <a-menu-item @click="forbiddenNode()">
          <span v-if="!node.data.forbidden">禁用</span>
          <span v-else>启用</span>
        </a-menu-item>
        <!-- <a-menu-item @click="onExport">下载</a-menu-item> -->
        <a-menu-item @click="deleteNode()">删除</a-menu-item>
        <a-sub-menu v-if="hasOutput(node.data)" title="保存">
          <a-menu-item @click="openSave(2)">保存至数据集</a-menu-item>
          <a-menu-item @click="openSave(1)">保存至数据管理</a-menu-item>
          <a-menu-item @click="saveToLocal()">保存至本地</a-menu-item>
        </a-sub-menu>
        <a-menu-item v-if="!comment && !node.data.forbidden" @click="addComment"
          >添加注释</a-menu-item
        >
        <a-menu-item v-if="comment && !node.data.forbidden" @click="addComment"
          >编辑注释</a-menu-item
        >
        <a-menu-item
          v-if="comment && !node.data.forbidden"
          @click="deleteComment"
          >删除注释</a-menu-item
        >
      </a-menu>
    </a-dropdown>

    <!-- 保存至数据管理 保存至数据集-->
    <a-modal
      :title="saveType === 1 ? '保存至数据管理' : '保存至数据集'"
      :visible="saveVisible"
      ok-text="确定"
      cancel-text="取消"
      centered
      :width="578"
      destroy-on-close
      @ok="saveData"
      @cancel.stop="cancelSave"
    >
      <div class="saveData-modal">
        <a-form
          :form="dataMgtForm"
          :label-col="{ span: 8 }"
          :wrapper-col="{ span: 16 }"
        >
          <a-form-item label="选择数据分类：">
            <a-select
              ref="select"
              v-model="dataMgtForm.categoryId"
              class="model-radius"
              placeholder="请选择"
              :disabled="newClassVisible"
              allow-clear
            >
              <a-select-option
                v-for="(item, index) in userDataList"
                :key="index"
                :value="item.categoryId"
              >
                {{ item.categoryName }}
              </a-select-option>
            </a-select>
            <span
              class="m-span"
              :class="{ disabled: newClassVisible }"
              @click="addClass"
              ><a-icon-font class="icon" type="iconzengjia"></a-icon-font
              >新建分类</span
            >
          </a-form-item>
          <a-form-item v-if="newClassVisible" label="数据分类名：">
            <a-input
              ref="classInput"
              v-model="dataMgtForm.categoryName"
              placeholder="未命名"
              allow-clear
              class="model-radius"
            >
            </a-input>
            <span class="delete" @click="newClassVisible = false"
              ><a-icon-font type="iconicon-beifen5"></a-icon-font
            ></span>
          </a-form-item>
          <a-form-item label="数据名：">
            <a-input
              v-model="dataMgtForm.datasetName"
              placeholder="请填写"
              :allow-clear="true"
              class="model-radius"
            >
            </a-input>
          </a-form-item>
        </a-form>
      </div>
    </a-modal>

    <!-- 提示框 -->
    <a-modal
      :visible="warningVisible"
      :ok-text="'替换'"
      cancel-text="取消"
      centered
      :width="458"
      on-ok="handleConfirm"
      @cancel.stop="warningVisible = false"
    >
      <div class="warning-modal">
        <a-icon-font class="icon" type="iconweiwanpeizhi"></a-icon-font>
        <strong>“数据集-1”已存在，要替换它吗？</strong>
      </div>
      <div style="margin: 0 44px;">
        “数据分类1”中已存在同名数据，若替换则会覆盖其当前内容。
      </div>
    </a-modal>

    <!-- 自定义算子编辑入口 -->
    <div v-if="!mode">
      <div
        v-show="isOperatorNode && isNodeHovered"
        class="node-edit-btn"
        :style="{
          left: !!nodeStatusIcon
            ? `${nodeWidth / 2 - 9}px`
            : `${nodeWidth - 10}px`,
          top: `${-nodeHeight - 7}px`,
        }"
        @click.stop="openNodeEditor()"
      >
        <img src="@/assets/edit.svg" class="node-edit-icon" alter="edit" />
      </div>
    </div>

    <!-- 注释 -->
    <div
      class="comment-container"
      :style="{
        left: `${(nodeWidth - 100) / 2}px`,
      }"
    >
      <a-textarea
        v-if="isCommentEditShow"
        id="commentTextarea"
        ref="commentTextarea"
        v-model="commentValue"
        class="comment-textarea"
        auto-focus
        placeholder="请输入注释"
        :auto-size="{ minRows: 1, maxRows: 3 }"
        @mousedown.stop
        @click.stop
        @blur="saveComment"
      />
      <a-popover title="注释文本">
        <template slot="content">
          <p style="word-wrap: break-word;">{{ comment }}</p>
        </template>
        <p v-if="isCommentReadShow" class="comment-readonly" @click.stop>
          {{ comment }}
        </p>
      </a-popover>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator'
import AddMenu from '@/components/studio/data/graph-compoments/AddMenu.vue'
import { simpleUpdate } from '@/api/task'
import {
  checkDatasetName,
  queryUserDatalist,
  saveToDataset,
  saveToDataSource,
} from '@/api/data-list'
import DataViewStore, { EditActionArea } from '@/store/modules/dataview'
import GraphViewStore from '@/store/modules/graphview'
import { NodeStatusEnum } from '@/components/studio/data/graph-compoments/node-status-emnu'
import {
  nodeIconWithBackGround,
  OperatorGroupIconEnum,
} from '@/components/studio/data/graph-compoments/node-icon-util'
import { baseURL } from '@/api/axios-config'

@Component({
  components: {
    AddMenu,
  },
  directives: {
    focus: {
      inserted: (element: any) => {
        element.focus()
      },
    },
  },
})
export default class NodeCapsule extends Vue {
  // 节点高度
  @Prop({ type: Number, default: 0 }) nodeHeight!: number
  // 节点宽度
  @Prop({ type: Number, default: 0 }) nodeWidth!: number
  // 节点
  @Prop({ type: Object, default: () => ({}) }) node!: any
  // 网格宽
  @Prop({ type: Number, default: 0 }) gridSizeWidth!: number
  // 网格高
  @Prop({ type: Number, default: 0 }) gridSizeHeight!: number
  // 差值 宽
  @Prop({ type: Number, default: 0 }) differenceOfGridWidth!: number
  // 差值 高
  @Prop({ type: Number, default: 0 }) differenceOfGridHeight!: number
  // 缩放比例
  @Prop({ type: Number, default: 0 }) zoomScale!: number
  // 右键菜单打开node id
  @Prop({ type: Number, default: 0 }) menuOpenId!: number
  // 访客模式
  @Prop({ type: Boolean, default: 0 }) mode!: boolean
  // 节点注释
  @Prop({ type: String, default: '' }) comment!: string
  // 节点状态
  @Prop({
    type: Object,
    default: () => {
      return { status: '', logInfo: null }
    },
  })
  nodeStatus!: any
  // 保存至数据管理,保存至数据源 弹窗显示
  public saveVisible: boolean = false
  // 保存type
  public saveType: number | null = null
  // 数据管理弹窗 form
  public dataMgtForm: any = {}
  // 新建分类是否显示
  public newClassVisible: boolean = false
  // 提示重复 弹窗显示
  public warningVisible: boolean = false
  // 用户数据列表(加载)
  public userDataList: Array<any> = []
  // 节点是否处于鼠标悬停状态
  public isNodeHovered: boolean = false
  // 右键菜单是否展示
  private contextmenuVisible: boolean = false

  // 是否显示编辑注释文本框
  private isCommentEditShow: boolean = false
  // 是否显示只读注释文本框
  private isCommentReadShow: boolean = false
  // 注释编辑态的内容
  private commentValue: string = this.comment
  // 记录编辑注释前的活动区域
  private prevActionArea: EditActionArea | undefined

  getPopupContainer(trigger: { parentElement: any }) {
    return trigger.parentElement
  }

  public hasOutput(value: any) {
    if (value?.output?.length > 0) {
      return true
    }
    return false
  }

  // 加载数据  获取用户所有数据
  public LoadData() {
    queryUserDatalist({ data: { projectId: this.node.projectId } })?.then(
      (response: any) => {
        if (response.data.code === 100) {
          this.userDataList = response.data.result
        }
      }
    )
  }

  // 弹窗-新建分类
  public addClass() {
    this.$nextTick(() => {
      if (this.dataMgtForm.categoryId) {
        this.dataMgtForm.categoryId = undefined
      }
      if (this.dataMgtForm.categoryName) {
        this.dataMgtForm.categoryName = undefined
      }

      const name = this.$refs.classInput as HTMLElement // 使用ref需要用v-show代替v-if
      // @ts-ignore
      setTimeout(function () {
        name?.focus()
      }, 300) // 延迟focus，否则不生效
    })
    this.newClassVisible = true
  }

  /**
   * 分组 icon
   */
  public groupIcon(type: number) {
    return OperatorGroupIconEnum[type]
  }

  // 是否为自定义算子节点
  private get isOperatorNode() {
    return this.node.type === 4 || this.node.type === 9
  }

  // 可视化对比状态
  private get comparisonStatus() {
    return DataViewStore.comparisonStatus
  }

  // 可视化对比状态
  private get comparisonNodeIds() {
    return DataViewStore.comparisonNodeIds
  }

  private timer: any = null
  private editStatus: boolean = false
  private editName: string = ''
  private tooltipStyle: any = {
    background: '#fff',
  }

  // 小数 缩放比例
  private get decimalZoomScale() {
    return this.zoomScale / 100
  }

  /**
   * 节点图标 和 背景色
   */
  private iconInfo(type: string) {
    if (this.node.type === 2 && this.node.data.algName === 'JOIN') {
      return nodeIconWithBackGround(0, this.node.data.mod)[type]
    }
    return nodeIconWithBackGround(this.node.type, this.node.data.algType)[type]
  }

  private get nodeStatusIcon() {
    return NodeStatusEnum[this.nodeStatus.status]
  }

  private get calcNameWidth() {
    // 节点宽度 -  边框4 - 4padding - 节点图标宽度 - 节点状态宽度  - 间距
    return this.nodeWidth - 8 - (this.nodeHeight - 8) * 2 - 8
  }

  /**
   * 双击节点  编辑名称
   */
  public doubleClickName(task: any, $event: MouseEvent) {
    if (this.mode) {
      return
    }
    clearTimeout(this.timer)
    $event.stopPropagation()
    this.editName = this.node.name
    this.editStatus = true
    this.$emit('node-event', { type: 'name', value: true })
  }

  /**
   * 单击选择节点
   * @param $event
   */
  public selectNode($event: MouseEvent) {
    clearTimeout(this.timer)
    $event.stopPropagation()
    this.timer = setTimeout(() => {
      this.$emit('select-node', { node: this.node, e: $event })
    }, 200)
  }

  /**
   * 双击选择节点
   */
  public selectCircleNode($event: MouseEvent) {
    if (this.node.type === 6) {
      clearTimeout(this.timer)
      $event.stopPropagation()

      this.timer = setTimeout(() => {
        GraphViewStore.setTaskId(this.node.id)
        this.$emit('dblclick-node', { node: this.node, e: $event })
      }, 200)
    }
  }

  /**
   * 编辑自定义算子节点， with this.node.operatorId & id
   */
  public openNodeEditor() {
    setTimeout(() => {
      this.$emit('node-edit')
    }, 300)
  }

  /**
   * 复制节点
   */
  public nodeCopy() {
    this.$emit('node-copy', this.node)
  }
  /**
   * 禁用节点
   */
  public forbiddenNode() {
    this.$emit('node-event', {
      type: 'forbidden',
      value: this.node.data.forbidden,
      nodeId: this.node.id,
    })
  }

  /**
   * 节点更新接口
   * @param parameters 更新参数
   */
  public nodeUpdate(parameters: any) {
    return simpleUpdate({ data: parameters })?.then((response: any) => {
      if (response.data.code === 100) {
        this.$emit('update-pipeline')
      }
    })
  }

  /**
   * 删除节点
   */
  public deleteNode() {
    this.$emit('delete-node', this.node)
  }

  /**
   * 保存数据
   */
  public async saveData() {
    if (!this.newClassVisible) {
      if (!this.dataMgtForm.categoryId) {
        this.$message.error('请选择数据分类！')
        return
      }
      if (!this.dataMgtForm.datasetName) {
        this.$message.error('请填写数据名！')
        return
      }
      // 非新建数据分类 需要检测同名数据集
      const response = await this.checkDatasetName()
      if (response.data.code === 100) {
        if (response.data.result) {
          this.$message.error(response.data.tips, 3)
        } else {
          this.saveDataApi()
        }
      }
    } else {
      if (!this.dataMgtForm.categoryName) {
        this.$message.error('请填写数据分类名！')
        return
      }
      if (!this.dataMgtForm.datasetName) {
        this.$message.error('请填写数据名！')
        return
      }
      this.saveDataApi()
    }
  }

  // 检测同名数据集
  public async checkDatasetName() {
    const response = await checkDatasetName({
      data: {
        categoryId: this.dataMgtForm.categoryId,
        datasetName: this.dataMgtForm.datasetName,
      },
    })
    return response
  }

  public saveDataApi() {
    const parameters = {
      categoryId: this.dataMgtForm.categoryId,
      datasetName: this.dataMgtForm.datasetName,
      categoryName: this.dataMgtForm.categoryName,
      projectId: this.node.projectId,
      taskId: this.node.id,
    }
    if (this.saveType === 1) {
      // 保存至数据管理
      saveToDataset({ data: parameters })?.then((response1: any) => {
        if (response1.data.code === 100) {
          this.$message.success('保存成功！')
          this.saveVisible = false
        } else {
          this.$message.error(response1.data.message)
        }
      })
    } else {
      saveToDataSource({ data: parameters })?.then((response1: any) => {
        if (response1.data.code === 100) {
          this.$message.success('保存成功！')
          DataViewStore.loadProjectData(this.node.projectId)
          this.saveVisible = false
        } else {
          this.$message.error(response1.data.message)
        }
      })
    }
  }

  // 保存数据
  public openSave(type: number) {
    this.LoadData()
    this.saveType = type
    this.dataMgtForm = {}
    this.saveVisible = true
  }

  public saveToLocal() {
    // 保存至本地
    window.open(`${baseURL}/task/download?taskId=${this.node.id}`)
  }

  // 取消保存
  public cancelSave() {
    this.newClassVisible = false
    this.saveVisible = false
    this.saveType = null
    this.dataMgtForm = {}
  }

  /**
   * 修改节点名称
   */
  private editNameEnter() {
    if (this.editName.length <= 0) {
      this.$message.warning('节点名称不能为空 !', 1.5)
      const name = this.$refs.nameInput as HTMLElement
      name.focus()
    } else {
      console.log(this.editName)
      if (this.editName !== this.node.name) {
        const parameters = {
          id: this.node.id,
          projectId: this.node.projectId,
          pipelineId: this.node.pipelineId,
          name: this.editName,
          data: {
            isSimple: true,
          },
        }
        this.nodeUpdate(parameters)
      }
      this.editStatus = false
    }
  }

  public changeNodeComparison($event: MouseEvent) {
    $event.stopPropagation()
    DataViewStore.changeComparisonNodes(this.node)
  }

  public visibleChange(value: boolean) {
    this.contextmenuVisible = value
    // if (value) {
    this.$emit('node-event', { type: 'menu', value, nodeId: this.node.id })
    // }
  }

  public getDetailText(node: any) {
    switch (node.data.algName) {
      case 'LINEARREGRE':
        return [
          `elastic_net=${node.data.elastic_net}`,
          `max_iter=${node.data.max_iter}`,
        ]
      case 'DBSCAN':
        return [
          `eps=${node.data.eps}`,
          `min_samples=${node.data.min_samples}`,
          `metric=${node.data.metric}`,
        ]
      case 'KMEANS':
        return [`k=${node.data.k}`]
      case 'ISO_FOREST':
        return [
          `n_estimators=${node.data.n_estimators}`,
          `max_samples=${node.data.max_samples}`,
          `contamination=${node.data.contamination}`,
        ]
      case 'FP_GROWTH':
        return [
          `min_frquency=${node.data.min_frquency}`,
          `min_support=${node.data.min_support}`,
          `min_confidence=${node.data.min_confidence}`,
        ]
      case 'PREFIX_SPAN':
        return [`min_support=${node.data.min_support}`]
      case 'PCA_DENSE':
        return [`dimesion_num=${node.data.dimension_num}`]
      case 'LLE':
        return [`dimesion_num=${node.data.dimension_num}`]
      case 'TSNE':
        return [`dimesion_num=${node.data.dimension_num}`]
      case 'LOGREGRE':
        return [
          `elastic_net=${node.data.elastic_net}`,
          `max_iter=${node.data.max_iter}`,
          `tolerance=${node.data.tolerance}`,
          `reg=${node.data.reg}`,
        ]
      case 'STAT_ANOMALY':
        return [`feature_col=${node.data.feature_col}`]
      default:
        return ''
    }
  }

  public onExport() {
    window.open(`${baseURL}/task/download?taskId=${this.node.id}`)
  }

  // 添加注释
  public addComment() {
    this.isCommentEditShow = true
    this.isCommentReadShow = false
    this.prevActionArea = DataViewStore.ActionArea
    DataViewStore.setActionArea(EditActionArea.COMMENT)
  }

  // 保存注释
  public async saveComment() {
    const parameters = {
      id: this.node.id,
      projectId: this.node.projectId,
      pipelineId: this.node.pipelineId,
      name: this.node.name,
      data: {
        comments: {
          content: this.commentValue,
        },
        isSimple: true,
      },
    }
    await DataViewStore.updateComment(parameters)
    this.isCommentEditShow = false
    this.isCommentReadShow = true
    if (this.prevActionArea !== undefined) {
      DataViewStore.setActionArea(this.prevActionArea)
    }

    // 刷新pipeline节点信息
    this.$emit('update-pipeline')
  }

  // 删除注释
  public deleteComment() {
    this.commentValue = ''
    this.saveComment()
  }

  public showHideComment() {
    this.isCommentReadShow = !this.isCommentReadShow
  }
}
</script>

<style scoped lang="less">
/* 节点执行动画 unused */
@keyframes node-running {
  0% {
    background-position: 100% 50%;
  }

  100% {
    background-position: 0 50%;
  }
}
/* 执行节点 unused  */
.node-capsule-running {
  animation: node-running 1.4s ease infinite;
  background-size: 400% 100% !important;
}

/* 节点 胶囊 */
.node-capsule-component {
  align-content: center;
  background-color: #fff;
  box-sizing: border-box;
  justify-content: center;
  // padding: 7px 6px;
  position: absolute;
  z-index: 30;

  /* dropdown 中的节点胶囊 */
  .dropdown-capsule {
    align-items: center;
    cursor: pointer;
    display: flex;
    flex-direction: row;
    font-size: 14px;
    height: 100%;
    justify-content: center;
    text-align: center;
    user-select: none;
    width: 100%;
  }

  /* 尾部添加节点 */
  .after-add-node {
    background-color: #f0f2f5;
    height: 14px;
    line-height: 14px;
    position: absolute;
    right: -16px;
    transition: opacity 0.5s;
    width: 14px;

    &::before {
      background-color: transparent;
      content: '';
      height: 32px;
      left: -5px;
      position: absolute;
      width: 6px;
    }
  }

  // 禁用
  .node-no-forbidden {
    height: 0;
    left: 0;
    position: absolute;
    top: 0;
    width: 0;
  }

  /* 节点禁用灰度 */
  .node-forbidden {
    background-color: rgba(255, 255, 255, 0.5);

    cursor: not-allowed;
    height: 100%;
    width: 100%;
  }

  .node-forbidden-name {
    color: rgba(0, 0, 0, 0.5);
  }

  /* 节点图标 */
  .type-icon {
    align-items: center;
    // background-color: rgba(154, 162, 255, 1);
    // background-color: #d5d5d5;
    // border-radius: 50%;
    display: flex;
    flex-direction: row;
    justify-content: center;
    margin: 0 auto;

    // .type-icon-color {
    // color: #fff;
    // }
  }

  /* 节点name */
  .node-name {
    align-items: center;
    background-color: transparent;
    display: flex;
    height: 20px;
    justify-content: center;
    max-width: 100px;
    position: absolute;
    transform: translateY(-30%);

    .normal-display {
      overflow: hidden;
      text-align: left;
      text-overflow: ellipsis;
      white-space: nowrap;
      width: 100%;
    }

    /* 节点名称编辑 */
    .edit-name {
      height: 100%;
      padding: 0 2px;

      /deep/.ant-input {
        height: 100%;
        padding: 1px 2px;
        text-align: center;
        width: 130px;
      }
    }
  }

  .clean-node-menu {
    display: flex;
    height: 40px;
    justify-content: center;
    position: absolute;
    top: -35px;
    width: 80px;

    .icon-list {
      bottom: 9px;
      display: flex;
      justify-content: center;
      position: absolute;
      width: 100%;

      .icon {
        margin: 0 2px;

        .icon-with-status {
          display: flex;
          flex-direction: row;
        }

        &.hover {
          background-color: #6973ff;
          border: 1px solid #d9d9d9;
        }
      }
    }

    .bottom-div {
      border: 1px solid #b6bdd2;
      border-top: 0;
      bottom: 5px;
      height: 4px;
      // margin: 0 10px;
      position: absolute;
      width: 60px;
    }
  }

  .tooltipClass {
    background-color: #fff;
  }

  /* 节点状态 */
  .status-icon-content {
    align-items: center;
    // border-radius: 50%;
    display: flex;
    justify-content: center;
    position: absolute;
    top: -15px;

    .status-icon {
      height: 18px;
      width: 18px;
    }
  }

  /* 对比图标 */
  .comparison-select {
    align-items: center;
    display: flex;
    justify-content: center;
    // border-radius: 50%;
  }
}

.saveData-modal {
  .m-span {
    cursor: pointer;
    margin-left: 8px;

    &:hover {
      color: #6973ff;
    }

    .icon {
      margin-right: 5px;
    }
  }

  .model-radius {
    border-radius: 4px;
    width: 190px;
  }

  .disabled {
    color: rgba(0, 0, 0, 0.2);
    cursor: not-allowed;

    &:hover {
      color: rgba(0, 0, 0, 0.2);
    }
  }

  .delete {
    cursor: pointer;
    margin-left: 10px;

    &:hover {
      color: #6973ff;
    }
  }
}

.comment-container {
  font-size: 11px;
  margin-top: 25px;
  position: absolute;
  width: 100px;

  .comment-textarea {
    font-size: 11px;
    //resize: none;
  }

  .comment-readonly {
    color: #7a7f96;
    /* stylelint-disable-next-line  */
    -webkit-box-orient: vertical;
    /* stylelint-disable-next-line value-no-vendor-prefix  */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

.node-edit-btn {
  background-color: #6973ff;
  border-radius: 8px;
  display: flex;
  height: 16px;
  justify-content: center;
  opacity: 60%;
  position: relative;
  vertical-align: middle;
  width: 16px;
}

.node-edit-icon {
  display: inline-block;
  max-width: 90%;
}
</style>
